package com.mmlc.widget;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.OverScroller;

import com.mmlc.meimei.lichengkongjian.R;
import com.mmlc.utils.DimonsUtil;

import java.util.ArrayList;
import java.util.List;


public class Indicator extends View {
    private final int DEFAULT_NUMBER = 4;

    private int number = DEFAULT_NUMBER;

    private List<String> titles;

    private List<Rect> rectList;

    private List<Integer> colors;

    private List<Integer> sizes;

    private String[] DEFAULT_TITLE = new String[]{""};

    private int mode = 0;// 1为按内容大小决定，0为均分

    private boolean hasBottom = true;

    public boolean isHasBottom() {
        return hasBottom;
    }

    public void setHasBottom(boolean hasBottom) {
        this.hasBottom = hasBottom;
        invalidate();
    }

    private Paint paint;

    private int index=-1;

    private int currentIndex = 0;

    private boolean isBold = false;

    private boolean isAniming;

    private boolean scrollable = true;

    private ValueAnimator animator;

    private int selectColor;

    private int selectedColor;

    private int selectSize;

    private int selectedSize;

    private int DEFAULT_DISTANCE;// 运动的最低距离

    private int realWidth;

    float startX;
    float startY;

    float endX;
    float endY;

    private VelocityTracker tracker;

    private OverScroller mScroller;

    private float bottomX;

    private float bottomW;

    private int mMaximumVelocity;

    private ViewPager mViewPager;

    private int expandLength;


    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public ViewPager getmViewPager() {
        return mViewPager;
    }


    public int getMode() {
        return mode;
    }

    public void setMode(int mode) {
        this.mode = mode;
        invalidate();
    }

    public int getExpandLength() {
        return expandLength;
    }

    public void setExpandLength(int expandLength) {
        this.expandLength = expandLength;
        invalidate();
    }

    public void setmViewPager(final ViewPager mViewPager, int index) {
        this.mViewPager = mViewPager;
        mViewPager.setOnPageChangeListener(new OnPageChangeListener() {

            @Override
            public void onPageSelected(int arg0) {
                // TODO Auto-generated method stub
            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {
                // TODO Auto-generated method stub
                if (scrollable) {
                    int trage = -1;
                    float rating = 0f;

                    if (arg0 == mViewPager.getCurrentItem()) {
                        trage = arg0 + 1;
                        rating = arg1;
                    } else {
                        trage = arg0;
                        rating = 1f - arg1;

                    }

                    if (trage > -1 && trage < rectList.size()
                            && (rating != 0f || rating != 1f)) {

                        int startx = rectList.get(Indicator.this.mViewPager.getCurrentItem()).left
                                + (rectList.get(Indicator.this.mViewPager.getCurrentItem()).width()
                                - titles.get(Indicator.this.mViewPager.getCurrentItem())
                                .length() * selectedSize) / 2 - expandLength;
                        int endx = rectList.get(trage).left
                                + (rectList.get(trage).width()
                                - titles.get(trage).length() * selectedSize) / 2 - expandLength;
                        bottomX = startx + (endx - startx)
                                * rating;
                        bottomW = titles.get(mViewPager.getCurrentItem()).length() * selectedSize + 2 * expandLength
                                + (titles.get(trage).length() * selectedSize
                                - titles.get(mViewPager.getCurrentItem()).length() * selectedSize)
                                * rating;
                        colors.set(mViewPager.getCurrentItem(), getOldColor(rating));
                        colors.set(trage, getNewColor(rating));
                        sizes.set(mViewPager.getCurrentItem(), getOldSize(rating));
                        sizes.set(trage, getNewSize(rating));

                        currentIndex = mViewPager.getCurrentItem();
                        postInvalidate();
                    }
                }

            }

            @Override
            public void onPageScrollStateChanged(int arg0) {
                // TODO Auto-generated method stub
                if (arg0 == 0 && scrollable) {

                    bottomX = rectList.get(mViewPager.getCurrentItem()).left
                            + (rectList.get(mViewPager.getCurrentItem()).width()
                            - titles.get(mViewPager.getCurrentItem()).length() * selectedSize) / 2 - expandLength;
                    bottomW = titles.get(mViewPager.getCurrentItem()).length() * selectedSize + 2 * expandLength;
                    for (int i = 0; i < rectList.size(); i++) {
                        colors.set(i, selectColor);
                        sizes.set(i, selectSize);
                    }
                    colors.set(Indicator.this.mViewPager.getCurrentItem(), selectedColor);
                    sizes.set(Indicator.this.mViewPager.getCurrentItem(), selectedSize);
                    setIndex(Indicator.this.mViewPager.getCurrentItem(), false);

                }
                if (arg0 == 0 && !scrollable) {
                    scrollable = true;
                }
            }
        });
        mViewPager.setCurrentItem(index);
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        setIndex(index, true);
        if (mIndexChangeListener != null) {
            mIndexChangeListener.onIndexSelected(index);
        }
    }


    public void setIndex(int newIndex, boolean hasAnim) {
        if (this.index==-1)
        {
            index=newIndex;
            invalidate();
            return;
        }
        if (this.index != newIndex) {
            if (hasAnim) {
                startAnimate(this.index, newIndex);
            }
        }
        if (mViewPager != null && hasAnim) {
            scrollable = false;
            mViewPager.setCurrentItem(newIndex);
        }
        if (newIndex >= rectList.size()) {
            return;
        }
        if (newIndex < 0) {
            return;
        }
        if (this.index != newIndex) {
            int dx = 0;
            Rect rect = rectList.get(newIndex);
            int sx = rect.left - (getMeasuredWidth() - rect.width()) / 2;
            if (sx < 0)
                sx = 0;
            if (sx > realWidth - getMeasuredWidth())
                sx = realWidth - getMeasuredWidth();
            dx = sx - getScrollX();
            if (mode == 1) {
                mScroller.startScroll(getScrollX(), 0, dx, 0, 300);
            }
            this.index = newIndex;
        } else {
            colors.set(newIndex, selectedColor);
            sizes.set(newIndex, selectedSize);

        }
        postInvalidate();
    }

    private int getOldColor(float rating) {
        return Color.rgb(
                Color.red(selectedColor)
                        + (int) ((Color.red(selectColor) - Color
                        .red(selectedColor)) * rating),
                Color.green(selectedColor)
                        + (int) ((Color.green(selectColor) - Color
                        .green(selectedColor)) * rating),
                Color.blue(selectedColor)
                        + (int) ((Color.blue(selectColor) - Color
                        .blue(selectedColor)) * rating));
    }

    private int getOldSize(float rating) {
        return selectedSize + (int) ((selectSize - selectedSize) * rating);
    }

    private int getNewColor(float rating) {
        return Color.rgb(
                Color.red(selectColor)
                        + (int) ((Color.red(selectedColor) - Color
                        .red(selectColor)) * rating),
                Color.green(selectColor)
                        + (int) ((Color.green(selectedColor) - Color
                        .green(selectColor)) * rating),
                Color.blue(selectColor)
                        + (int) ((Color.blue(selectedColor) - Color
                        .blue(selectColor)) * rating));
    }

    private int getNewSize(float rating) {
        return selectSize + (int) ((selectedSize - selectSize) * rating);
    }

    public Indicator(Context context) {
        super(context);
        init(context,null);
    }

    public Indicator(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);

    }

    private void startAnimate(int oldIndex, int newIndex) {
        animator.removeAllUpdateListeners();
        animator.addUpdateListener(new MyAnimatorUpdateListener(oldIndex,
                newIndex));
        animator.start();

    }

    private onIndexChangeListener mIndexChangeListener;

    public int getSelectedSize() {
        return selectedSize;
    }

    public void setSelectedSize(int selectedSize) {
        this.selectedSize = selectedSize;
    }

    public onIndexChangeListener getIndexChangeListener() {
        return mIndexChangeListener;
    }

    public void setIndexChangeListener(onIndexChangeListener indexChangeListener) {
        mIndexChangeListener = indexChangeListener;
    }

    public interface onIndexChangeListener {
        public void onIndexSelected(int index);

    }


    private class MyAnimatorUpdateListener implements
            ValueAnimator.AnimatorUpdateListener {
        private int oldIndex;
        private int newIndex;

        public MyAnimatorUpdateListener(final int oldIndex, final int newIndex) {
            this.oldIndex = oldIndex;
            this.newIndex = newIndex;
        }

        @Override
        public void onAnimationUpdate(ValueAnimator animation) {


            float rating = animation.getAnimatedFraction();
            int startx = rectList.get(oldIndex).left
                    + (rectList.get(oldIndex).width()
                    - titles.get(oldIndex).length() * selectedSize) / 2 - expandLength;
            int endx = rectList.get(newIndex).left
                    + (rectList.get(newIndex).width()
                    - titles.get(newIndex).length() * selectedSize) / 2 - expandLength;
            bottomX = startx + (endx - startx) * rating;
            bottomW = titles.get(oldIndex).length() * selectedSize + 2 * expandLength
                    + (titles.get(newIndex).length() * selectedSize
                    - titles.get(oldIndex).length() * selectedSize)
                    * rating;
            colors.set(oldIndex, getOldColor(rating));
            colors.set(newIndex, getNewColor(rating));
            sizes.set(oldIndex, getOldSize(rating));
            sizes.set(newIndex, getNewSize(rating));
            invalidate();
        }
    }

    public Indicator(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }

    @TargetApi(21)
    public Indicator(Context context, AttributeSet attrs, int defStyleAttr,
                     int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context,attrs);
    }

    public int getSelectSize() {
        return selectSize;
    }

    public void setSelectSize(int selectSize) {
        this.selectSize = selectSize;
    }

    private void init(Context context,AttributeSet attrs) {
        if(attrs != null){
            TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.Indicator);
            if(ta != null){
                selectSize = ta.getInteger(R.styleable.Indicator_selectSize,
                        DimonsUtil.dp2px(14, getContext()));
                selectedSize = ta.getInteger(R.styleable.Indicator_selectedSize,
                        DimonsUtil.dp2px(14, getContext()));
                selectColor = ta.getInteger(R.styleable.Indicator_selectColor,
                        getResources().getColor(R.color.text_grey));
                selectedColor = ta.getInteger(R.styleable.Indicator_selectedColor,
                        getResources().getColor(R.color.text_title));
                isBold = ta.getBoolean(R.styleable.Indicator_isBold,false);
            }
        }else {
            selectSize = DimonsUtil.dp2px(14, getContext());
            selectedSize = DimonsUtil.dp2px(14, getContext());
            selectColor = getResources().getColor(R.color.text_grey);
            selectedColor = getResources().getColor(R.color.text_title);
        }
        setBackgroundColor(Color.WHITE);
/*        setTitles(new ArrayList<String>(Arrays.asList(DEFAULT_TITLE)));*/
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setTextAlign(Paint.Align.CENTER);
        animator = ValueAnimator.ofFloat(0f, 1f);
        animator.setDuration(300);
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                isAniming = true;
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                isAniming = false;
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                isAniming = false;
            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        final ViewConfiguration configuration = ViewConfiguration
                .get(getContext());
        DEFAULT_DISTANCE = configuration.getScaledTouchSlop();
        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();

        mScroller = new OverScroller(getContext());

    }

    public List<String> getTitles() {
        return titles;
    }

    public void setTitles(List<String> titles) {
        this.titles = titles;
        if (rectList == null) {
            rectList = new ArrayList<Rect>();
        } else {
            rectList.clear();
        }
        for (int i = 0; i < titles.size(); i++) {
            Rect rect = new Rect();
            rectList.add(rect);
        }
        if (colors == null) {
            colors = new ArrayList<Integer>();
        } else {
            colors.clear();
        }
        for (int i = 0; i < titles.size(); i++) {
            colors.add(selectColor);
        }
        if (sizes == null) {
            sizes = new ArrayList<Integer>();
        } else {
            sizes.clear();
        }
        for (int i = 0; i < titles.size(); i++) {
            sizes.add(selectSize);
        }
        reSizeRect();
        invalidate();
        setIndex(0);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        paint.setTextSize(Math.min(h / 3, selectedSize));
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
                            int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        reSizeRect();
        Log.d("animation", "bottomX" + bottomX);
        Log.d("animation", "bottomW" + bottomW);
    }

    private void reSizeRect() {
        if (rectList==null||rectList.size()==0)
            return;
        int x = 0;
        for (int i = 0; i < rectList.size(); i++) {
            int row = (titles.get(i).length() + 1) * selectedSize;
            x += row;
        }
        if (x > getMeasuredWidth()) {

            reSetSizeModeSize();
        } else {

            reSetSizeModeAvg();
        }


        if (bottomX == 0f && bottomW == 0f&&index!=-1) {
            int textWidth = (titles.get(index).length()) * selectedSize + expandLength * 2;
            bottomX = rectList.get(index).left + (rectList.get(index).width() - textWidth) / 2;
            bottomW = textWidth;
        }

    }


    private void reSetSizeModeAvg() {
        mode = 0;
        int rectw;
        rectw = getMeasuredWidth() / titles.size();
        for (int i = 0; i < titles.size(); i++) {
            Rect rect = rectList.get(i);
            rect.set(rectw * i, 0, rectw * (i + 1), getMeasuredHeight());
        }
        realWidth = titles.size() * rectw;
    }

    private void reSetSizeModeSize() {
        mode = 1;
        int x = 0;
        for (int i = 0; i < rectList.size(); i++) {
            int row = (titles.get(i).length() + 1) * selectedSize;
            rectList.get(i).set(x, 0, x + row, getMeasuredHeight());
            x += row;
        }
        realWidth = x;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (rectList==null||rectList.size()==0)
            return;
        for (int i = 0; i < rectList.size(); i++) {
            Rect rect = rectList.get(i);
            paint.setTextSize(sizes.get(i));

            Paint.FontMetrics fontMetrics = paint.getFontMetrics();
            float y = ((rect.top + rect.bottom - fontMetrics.top - fontMetrics.bottom) / 2);
            paint.setColor(colors.get(i));
            if(isBold){
                if(currentIndex == i){
                    paint.setTypeface(Typeface.DEFAULT_BOLD);
                }else {
                    paint.setTypeface(Typeface.DEFAULT);
                }
            }
            canvas.drawText(titles.get(i), rect.centerX(), y, paint);
        }
        if (hasBottom) {
            Log.d("animation", "onDraw" + bottomX);
            paint.setColor(selectedColor);
            canvas.drawRect(bottomX, (float) getMeasuredHeight()
                            - (float) getBottomHeight(), bottomX + bottomW,
                    (float) getMeasuredHeight() - (float) getMeasuredHeight()
                            / 30, paint);
        }

        if (hasDivide) {
            for (int i = 0; i < rectList.size() - 1; i++) {
                Rect rect = rectList.get(i);
                canvas.drawRect(rect.right - 2, (rect.height() - selectedSize * 3 / 2) / 2
                        , rect.right + 2, (rect.height() - selectedSize * 3 / 2) / 2 + selectedSize * 3 / 2
                        , paint);
            }
        }


    }

    private boolean hasDivide = false;

    public boolean isHasDivide() {
        return hasDivide;
    }

    public void setHasDivide(boolean hasDivide) {
        this.hasDivide = hasDivide;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = event.getX();
                startY = event.getY();
                endX = event.getX();
                endY = event.getY();
                if (tracker == null) {
                    tracker = VelocityTracker.obtain();
                }
                tracker.addMovement(event);
                break;
            case MotionEvent.ACTION_MOVE:
                double distance = Math.sqrt(Math.pow(Math.abs(event.getX() - endX),
                        2) + Math.pow(Math.abs(event.getY() - endY), 2));
                if (distance > DEFAULT_DISTANCE) {
                    int scrollerRange = realWidth - getMeasuredWidth();
                    int scrollValue = (int) (endX - event.getX() + getScrollX());
                    if (scrollValue < 0) {
                        setScrollX(0);
                    } else if (scrollValue > scrollerRange) {
                        setScrollX(scrollerRange);
                    } else {
                        setScrollX(scrollValue);
                    }
                    endX = event.getX();
                    endY = event.getY();
                }
                tracker.addMovement(event);
                break;
            case MotionEvent.ACTION_UP:
                if (startX == endX && startY == endY) {
                    for (int i = 0; i < rectList.size(); i++) {
                        Rect rect = rectList.get(i);
                        if (rect.contains((int) startX + getScrollX(), (int) startY)) {
                            if (!isAniming) {
                                setIndex(i);
                            }
                        }
                    }

                } else {
                    tracker.computeCurrentVelocity(1000, mMaximumVelocity);
                    mScroller.fling(getScrollX(), getScrollY(),
                            (int) -tracker.getXVelocity(), 0, 0, realWidth
                                    - getMeasuredWidth(), 0, 0,
                            getMeasuredHeight(), 0);
                    releaseVelocityTracker();
                    postInvalidate();

                }
                break;
        }
        return true;

    }

    private void releaseVelocityTracker() {
        if (null != tracker) {
            tracker.clear();
            tracker.recycle();
            tracker = null;
        }
    }

    private int bottomHeight;

    public int getBottomHeight() {
        if (bottomHeight == 0)
            return getMeasuredHeight() / 10;
        else
            return bottomHeight;
    }

    public void setBottomHeight(int bottomHeight) {
        this.bottomHeight = bottomHeight;
        invalidate();
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            invalidate();
        }
    }
}
